/*
 * Depstruct.cpp
 *
 *  Created on: Dec 18, 2014
 *      Author: Phong
 */

#include "Depstruct.h"
#include "Deptree.h"
#include "Utils.h"

using namespace std;

Depstruct::~Depstruct() {
    delete[] word;
    delete[] pos;
    delete[] head;
    delete[] deprel;
    delete[] nDeps;
    for (int i = 0; i < nWords; i++)
        delete[] dep[i];
    delete[] dep;
}

Depstruct::Depstruct(int** input, int n, vector<string>& tks) : SafeShare() {
	nWords	= n + 1;
	word	= new int[nWords]();
	pos		= new int[nWords]();
	head	= new int[nWords]();
	deprel	= new int[nWords]();
	nDeps	= new int[nWords]();
	dep		= new int*[nWords];
	for (int i = 0; i < nWords; i++) {
		dep[i] = new int[nWords]();
	}

	tokens = tks;

	// ROOT
	word[0] = pos[0] = deprel[0] = 0; // fake values for ROOT

	for(int i = 1; i <= n; i++) {
		int* row = input[i-1];
		word[i]		= row[0];
		pos[i]		= row[1];
		head[i]		= row[2];
		deprel[i]	= row[3];

		// if not ROOT
		int hid = head[i];
		if (hid > -1) {
			dep[hid][nDeps[hid]] = i;
			nDeps[hid]++;
		}
	}
}

Depstruct* Depstruct::create(DEP* deps, int n, Dictionary* vocaDic, Dictionary* posDic, Dictionary* deprelDic) {
	int** input = new int*[n];
	vector<string> tokens;
    
	tokens.push_back("ROOT");
	// set mocking value for ROOT

	for (int i = 0; i < n; i++){
		DEP comps = deps[i];
		tokens.push_back(comps.word);
		int* row = new int[4] {	vocaDic->getId(comps.word),
			posDic->getId(comps.pos),
			comps.headid,
			deprelDic->getId(comps.deprel)};
		input[i] = row;
	}

	Depstruct* ret = new Depstruct(input, n, tokens);
	for (int i = 0; i < n; i++) delete[] input[i];
	delete[] input;

	return ret;
}

Deptree* Depstruct::toDepTree() {
	Deptree* tree = new Deptree(nWords);
	toDepTree(0, 0, tree);
	tree->ds = (Depstruct*)this->share();
	return tree;
}

string Depstruct::toString(Dictionary* posDic, Dictionary* deprelDic) {
    string str;
	for (int i = 1; i < nWords; i++) {
		str += to_string(i) + "\t"
				+ tokens[i] + "\t"
				+ "_\t" + "_\t"
				+ posDic->id2word[pos[i]] + "\t"
				+ "_\t"
				+ to_string(head[i]) + "\t"
				+ deprelDic->id2word[deprel[i]] + "\n";
	}
	return str;
}

int Depstruct::toDepTree(int id, int node, Deptree* tree) {
	int n = nDeps[id];
	tree->word[node] = word[id];
	tree->pos[node] = pos[id];
	tree->deprel[node] = deprel[id];

	if (n == 0) node++;
	else{
		int curNode = node + 1;
		// left child: rigth -> left
		tree->nChildren[node][0] = 0;
		for (int i = n-1; i >= 0; i--) {
			if (dep[id][i] < id) {
				tree->children[node][0][tree->nChildren[node][0]] = curNode;
				tree->nChildren[node][0]++;
				tree->parent[curNode] = node;
				tree->dir[curNode] = 0;
				curNode = toDepTree(dep[id][i], curNode, tree);
			}
		}

		// right child: left -> right
		tree->nChildren[node][1] = 0;
		for (int i = 0; i < n; i++) {
			if (dep[id][i] > id) {
				tree->children[node][1][tree->nChildren[node][1]] = curNode;
				tree->nChildren[node][1]++;
				tree->parent[curNode] = node;
				tree->dir[curNode] = 1;
				curNode = toDepTree(dep[id][i], curNode, tree);
			}
		}

		node = curNode;
	}

	return node;
}

